home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Programmer Disk
/
The Programmer Disk (Microforum).iso
/
xpro
/
pascal2
/
pro6
/
tdates.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1986-08-04
|
7KB
|
228 lines
{ Full source within a sample program, containing the following
routines:
n:=ymd2n(y,m,d); returns integer relative to Sep 19, 1989. The allowable
date range is 1900 thru 2078.
n2ymd(0,y,m,d); reverse of above. 0 results in 1989,9,19 for y,m,d.
w:=n2dow(n) and w:=ymd2dow(y,m,d); returns 1=mon,2=tue,...7=sun
dys:=nn2d(n1,n2) or dys:=dif(y1,m1,d1,y2,m2,d2); returns days between dates
wkdys:=nn2w(n1,n2) or wkdys:=wdif(y1,m1,d1,y2,m2,d2); returns weekdays in range
dys:=dim(y,m); returns days in the specified year/month.
If ymdok(y,m,d) then... returns true if date in range and all fields valid.
s:=n2s(n) or n:=ymd2s(y,m,d); returns date as string in format:
"Saturday, the 24th of April, 1948"
n:=newn(n,adj) or newymd(adj,y,m,d); adjusts given date forward or backward
n:=n2w(n,5) or ymd2w(5,y,m,d); if not already friday, date is moved forward
n:=n2pw(n,1) or ymd2pw(1,y,m,d); if not already monday, moved back in time
Take care that you don't exceed maxint in the routines where 2 days are given.
In other words, dif(1910,1,1,2045,12,31) returns a negative number. As long as
dates are less than 90 years apart, you're fine. If you don't like the range
1900..2078, then change then the BaseYear const to other than 1900. The ymd2n
routine is derived from a julian date algortihm posted by Bob Brown in
soft.eng/algortihm, of which he is a moderator.
If you change the BaseYear, you should also change the range checking in
ymdok. You might also want to change the 'adjust' const to line up the dates
for your new range. Lastly, you'll have to 'tweak' the 'n2dow' routine unless
you happen to be lucky!
Any feedback/corrections/suggestions are appreciated, thanks! - Jim Keohane
}
Program tdates;
var y,m,d,y2,m2,d2:integer;
type anystring=string[255];
const baseyear=1980; adjust=-100;
Function ymd2n(y,m,d:integer):integer;
{returns day number relative to Sep 19, 1989}
begin
ymd2n := 367*(y-baseyear)
-7*(y+(m+9) div 12) div 4
-3*((y+(m-9) div 7) div 100+1) div 4
+275*m div 9
+d
+adjust
end;
Function dim(y,m:integer):integer;
{returns days in given month}
begin
if m=12 then dim:=ymd2n(y+1,1,1)-ymd2n(y,m,1)
else dim:=ymd2n(y,m+1,1)-ymd2n(y,m,1)
end;
Procedure n2ymd(n:integer;var y,m,d:integer);
{given relative day, returns y,m,d}
var i:integer;
begin
y:=1989 + n div 365; m:=1; d:=1; {quick guess at year}
i:=ymd2n(y,m,d);
while i>n do
begin
y:=y-1;
i:=ymd2n(y,m,d)
end;
m:=1+(n-i) div 31; {quick guess at month}
while m>12 do begin y:=y+1; m:=m-12 end;
i:=ymd2n(y,m,d);
while dim(y,m) < n-i+1 do
begin
m:=m+1;
if m>12 then begin y:=y+1; m:=1 end;
i:=ymd2n(y,m,d)
end;
d:=1+n-i;
end;
Function n2dow(n:integer):integer;
{returns day of week 1=mon...6=sat,7=sun}
begin
n2dow:=1+(n mod 7+8) mod 7;
end;
Function ymd2dow(y,m,d:integer):integer;
begin
ymd2dow:=n2dow(ymd2n(y,m,d))
end;
Function ymdok(y,m,d:integer):boolean;
{returns true if valid date}
begin
if (y<1900) or (y>2078) or (m<1) or (m>12) or (d<1) then
ymdok:=false else ymdok:=d<=dim(y,m)
end;
Function ymd2s(y,m,d:integer):anystring;
{returns date string "Saturday, the 21st of April, 1979"}
var s:anystring;
day,year,th:string[4];
const days:array[1..7] of string[6]=
('Mon','Tues','Wednes','Thurs','Fri','Satur','Sun');
months:array[1..12] of string[9]=
('January','February','March','April','May','June',
'July','August','September','October','November','December');
begin
if d in [1,21,31] then th:='st' else
if d in [2,22] then th:='nd' else
if d in [3,23] then th:='rd' else th:='th';
str(d,day);
str(y,year);
ymd2s:=days[ymd2dow(y,m,d)]+'day, the '+day+th+' of '+months[m]+', '+year
end;
Function nn2d(n1,n2:integer):integer;
{returns signed difference in days of n2-n1}
begin
nn2d:=n2-n1
end;
Function dif(y1,m1,d1,y2,m2,d2:integer):integer;
{returns signed difference in days of ymd2-ymd1}
begin
dif:=nn2d( ymd2n(y1,m1,d1) , ymd2n(y2,m2,d2) )
end;
Function newn(oldn,adj:integer):integer;
{returns oldn adjusted by adj days}
begin
newn:=oldn+adj
end;
Procedure newymd(adj:integer;var y,m,d:integer);
{adjusts y,m,d by adj days}
begin
n2ymd ( newn( ymd2n(y,m,d) , adj) , y, m, d )
end;
Function n2w(n,w:integer):integer;
{given desired weekday (w=1,2...7) returns n, moved forward, if neccessary}
begin
n2w:=newn(n, (w-n2dow(n)+7) mod 7)
end;
Function n2pw(n,w:integer):integer;
{same as n2w, only movement is backwards, if neccessary}
begin
n2pw:= newn( n, ((w-n2dow(n)+7) mod 7 - 7) mod 7)
end;
Procedure ymd2w(w:integer;var y,m,d:integer);
{if not desired weekday (w), moves ymd forward}
begin
n2ymd ( n2w( ymd2n(y,m,d) , w ) , y, m, d )
end;
Procedure ymd2pw(w:integer;var y,m,d:integer);
{if not desired weekday (w), moves ymd backward}
begin
n2ymd ( n2pw( ymd2n(y,m,d) , w ) , y, m, d )
end;
Procedure MondaySince(var y,m,d:integer);
{returns 1st monday since ymd}
begin
ymd2w(1,y,m,d)
end;
Procedure LatestFriday(var y,m,d:integer);
{returns latest friday before (and including) ymd}
begin
ymd2pw(5,y,m,d)
end;
Function n2s(n:integer):anystring;
var y,m,d:integer;
begin
n2ymd(n,y,m,d);
n2s:=ymd2s(y,m,d)
end;
Function nn2w(n1,n2:integer):integer;
{returns the number of business days (signed) in the inclusive range}
var i,j,k:integer;
begin
if n1>n2 then nn2w:=-nn2w(n2,n1) else
begin
i:=n2dow(n1);
if i>5 then {sat or sun}
begin
n1:=n1+8-i;
i:=1 {make it a monday}
end;
j:=n2dow(n2);
if j>5 then {sat or sun}
begin
n2:=n2+5-j; {make it friday}
j:=5
end;
if n2<n1 then nn2w:=0 else
begin
k:=5 * ( (n2-n1) div 7 ) + j - i + 1;
if i>j then nn2w:=k+5 else nn2w:=k
end
end
end;
Function wdif(y1,m1,d1,y2,m2,d2:integer):integer;
{same as nn2w, but for ymd type dates}
begin
wdif:=nn2w( ymd2n(y1,m1,d1) , ymd2n(y2,m2,d2) )
end;
begin
write('2 dates < y1 m1 d1 y2 m2 d2>...');readln(y,m,d,y2,m2,d2);
if not ymdok(y,m,d) then writeln('1st date invalid ',y,' ',m,' ',d) else
if not ymdok(y2,m2,d2) then writeln('2nd date invalid ',y2,' ',m2,' ',d2)
else
begin
writeln('first date is ',ymd2s(y,m,d));
writeln(' and has ',dim(y,m),' days in the given month');
writeln('second date is ',ymd2s(y2,m2,d2));
writeln(' and has ',dim(y2,m2),' days in the given month');
writeln('There is a difference of ',dif(y,m,d,y2,m2,d2), ' day(s)');
writeln('There are ',wdif(y,m,d,y2,m2,d2),' weekday(s) in the range');
MondaySince(y,m,d);
writeln('most recent monday since 1st is ',ymd2s(y,m,d));
LatestFriday(y2,m2,d2);
writeln('latest friday including 2nd is ',ymd2s(y2,m2,d2));
end;
end.